<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="keywords" content="Hexo Theme Redefine">
    
    <meta name="author" content="xiaoeryu">
    <!-- preconnect -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

    
    <!--- Seo Part-->
    
    <link rel="canonical" href="https://xiaoeeyu.github.io/2022/12/11/25-保护模式程序的动态加载和执行/"/>
    <meta name="robots" content="index,follow">
    <meta name="googlebot" content="index,follow">
    <meta name="revisit-after" content="1 days">
    
    
    
        
        <meta name="description" content="01. 本章的目标和内容提要引入保护模式、描述符、描述符表等并没有对用户程序的编写增加什么负担  因为对于系统来说这些是必须的，对于运行在系统上的程序来说不需要关心这些">
<meta property="og:type" content="article">
<meta property="og:title" content="保护模式程序的动态加载和执行">
<meta property="og:url" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/index.html">
<meta property="og:site_name" content="xiaoeryu">
<meta property="og:description" content="01. 本章的目标和内容提要引入保护模式、描述符、描述符表等并没有对用户程序的编写增加什么负担  因为对于系统来说这些是必须的，对于运行在系统上的程序来说不需要关心这些">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/9bb28704b96ba84ebdd5cd6715a3c693.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/1fa11bf5789cca5df597cba02705eafa.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/bb79369a945668586c907eff40be4df8.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/b0486969de5d713ba29775fe980d06fd.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/72752de04c5902657684c80fe03e60d4.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/53951340edc787f76dad35ab5b8028c6.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/8e19731756b24be358680fb326a7e15d.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/07bfd474ab406622ec6744724c74846d.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/ca7c9e31c5f3d321a4ea2243ef708dac.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/24a4d1969cb1dce52429158938f30178.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/06ac92012b3feaf193f6590e8e96669e.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/cced9754233b346a0965ffc53d66187c.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/5e72268ea5185704e17458c5ff490729.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/0d699825616fb370b99fdac1f9689859.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/a37067392ac8d6dba19b384c333b109c.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/0b088096f037a5b3383b83b003e3ca11.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/0671b8c5bff812d609716ade0c2bd572.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/826acaeec0d57740394d8a9bb0052db9.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/4dfe3bf8b2ce32811fa15da1fe42f3a5.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/4e008d4175628203a066130d057cce66.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/04ac4b9bbf72aa3bf7d650f4b83b071f.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/144616b2a2b154bd174b8d71383ff689.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/8ee964a20a641a57cd2df08e5c65c163.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/a7b3bddccde1412511d349b08ec6851b.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/894b778c290e658fb31380b2feab024e.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/87fd4f6a3c17dfc49006dfa49461fa5e.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/0c0ba9317c35169c418216cb17d82d0c.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/99972661419e171cf0c3cdaaafd94d1f.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/6d34a115a6fee41642876058aa070a2c.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/e38333b91447d2184bcae4ae6b518ed4.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/90d787418a73c3b0e54694974514c50a.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/196c7eb008b6f6764d38d54857bbfa46.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/0df1110c1d014a7245f3fcb33df9f078.png">
<meta property="article:published_time" content="2022-12-11T14:43:00.000Z">
<meta property="article:modified_time" content="2023-10-03T04:59:44.176Z">
<meta property="article:author" content="xiaoeryu">
<meta property="article:tag" content="保护模式下的动态加载和执行">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://xiaoeeyu.github.io/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/9bb28704b96ba84ebdd5cd6715a3c693.png">
    
    
    <!--- Icon Part-->
    <link rel="icon" type="image/png" href="/images/rabete.jpg" sizes="192x192">
    <link rel="apple-touch-icon" sizes="180x180" href="/images/rabete.jpg">
    <meta name="theme-color" content="#A31F34">
    <link rel="shortcut icon" href="/images/rabete.jpg">
    <!--- Page Info-->
    
    <title>
        
            保护模式程序的动态加载和执行 | xiaoeryu
        
    </title>

    
<link rel="stylesheet" href="/fonts/Chillax/chillax.css">


    <!--- Inject Part-->
    

    
<link rel="stylesheet" href="/css/style.css">


    
        
<link rel="stylesheet" href="/css/build/tailwind.css">

    

    
<link rel="stylesheet" href="/fonts/GeistMono/geist-mono.css">

    
<link rel="stylesheet" href="/fonts/Geist/geist.css">

    <!--- Font Part-->
    
    
    
    
    
    

    <script id="hexo-configurations">
    window.config = {"hostname":"xiaoeeyu.github.io","root":"/","language":"zh-CN","path":"search.xml"};
    window.theme = {"articles":{"style":{"font_size":"16px","line_height":1.5,"image_border_radius":"14px","image_alignment":"center","image_caption":false,"link_icon":true,"delete_mask":false,"title_alignment":"left","headings_top_spacing":{"h1":"3.2rem","h2":"2.4rem","h3":"1.9rem","h4":"1.6rem","h5":"1.4rem","h6":"1.3rem"}},"word_count":{"enable":true,"count":true,"min2read":true},"author_label":{"enable":true,"auto":false,"list":[]},"code_block":{"copy":true,"style":"mac","highlight_theme":{"light":"github","dark":"vs2015"},"font":{"enable":false,"family":null,"url":null}},"toc":{"enable":true,"max_depth":4,"number":false,"expand":true,"init_open":true},"copyright":{"enable":true,"default":"cc_by_nc_sa"},"lazyload":true,"pangu_js":false,"recommendation":{"enable":false,"title":"推荐阅读","limit":3,"mobile_limit":2,"placeholder":"/images/ball-0101.jpg","skip_dirs":[]}},"colors":{"primary":"#A31F34","secondary":null,"default_mode":"light"},"global":{"fonts":{"chinese":{"enable":false,"family":null,"url":null},"english":{"enable":false,"family":null,"url":null},"title":{"enable":false,"family":null,"url":null}},"content_max_width":"1000px","sidebar_width":"210px","hover":{"shadow":true,"scale":false},"scroll_progress":{"bar":false,"percentage":true},"website_counter":{"url":"https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js","enable":true,"site_pv":true,"site_uv":true,"post_pv":true},"single_page":true,"preloader":{"enable":false,"custom_message":null},"open_graph":true,"google_analytics":{"enable":false,"id":null}},"home_banner":{"enable":true,"style":"fixed","image":{"light":"/images/wallhaven-jxl31y.png","dark":"/images/wallhaven-o5762l.png"},"title":"XIAOERYU","subtitle":{"text":["明心见性，拨云见日","Don't wait, to create"],"hitokoto":{"enable":false,"show_author":false,"api":"https://v1.hitokoto.cn"},"typing_speed":100,"backing_speed":80,"starting_delay":500,"backing_delay":1500,"loop":true,"smart_backspace":true},"text_color":{"light":"#fff","dark":"#d1d1b6"},"text_style":{"title_size":"2.8rem","subtitle_size":"1.5rem","line_height":1.2},"custom_font":{"enable":false,"family":null,"url":null},"social_links":{"enable":true,"style":"default","links":{"github":"https://github.com/xiaoeeyu","instagram":null,"zhihu":null,"twitter":null,"email":"xiaoeryu@163.com"},"qrs":{"weixin":null}}},"plugins":{"feed":{"enable":false},"aplayer":{"enable":false,"type":"fixed","audios":[{"name":null,"artist":null,"url":null,"cover":null,"lrc":null}]},"mermaid":{"enable":false,"version":"9.3.0"}},"version":"2.8.2","navbar":{"auto_hide":false,"color":{"left":"#f78736","right":"#367df7","transparency":35},"width":{"home":"1200px","pages":"1000px"},"links":{"Home":{"path":"/","icon":"fa-regular fa-house"},"Archives":{"path":"/archives","icon":"fa-regular fa-archive"}},"search":{"enable":true,"preload":true}},"page_templates":{"friends_column":2,"tags_style":"blur"},"home":{"sidebar":{"enable":true,"position":"left","first_item":"menu","announcement":null,"show_on_mobile":true,"links":null},"article_date_format":"auto","excerpt_length":200,"categories":{"enable":true,"limit":3},"tags":{"enable":true,"limit":3}},"footerStart":"2022/8/17 11:45:14"};
    window.lang_ago = {"second":"%s 秒前","minute":"%s 分钟前","hour":"%s 小时前","day":"%s 天前","week":"%s 周前","month":"%s 个月前","year":"%s 年前"};
    window.data = {"masonry":false};
  </script>
    
    <!--- Fontawesome Part-->
    
<link rel="stylesheet" href="/fontawesome/fontawesome.min.css">

    
<link rel="stylesheet" href="/fontawesome/brands.min.css">

    
<link rel="stylesheet" href="/fontawesome/solid.min.css">

    
<link rel="stylesheet" href="/fontawesome/regular.min.css">

    
    
    
    
<meta name="generator" content="Hexo 6.3.0">
<style>.github-emoji { position: relative; display: inline-block; width: 1.2em; min-height: 1.2em; overflow: hidden; vertical-align: top; color: transparent; }  .github-emoji > span { position: relative; z-index: 10; }  .github-emoji img, .github-emoji .fancybox { margin: 0 !important; padding: 0 !important; border: none !important; outline: none !important; text-decoration: none !important; user-select: none !important; cursor: auto !important; }  .github-emoji img { height: 1.2em !important; width: 1.2em !important; position: absolute !important; left: 50% !important; top: 50% !important; transform: translate(-50%, -50%) !important; user-select: none !important; cursor: auto !important; } .github-emoji-fallback { color: inherit; } .github-emoji-fallback img { opacity: 0 !important; }</style>
</head>



<body>
	<div class="progress-bar-container">
	

	
	<span class="pjax-progress-bar"></span>
	<!--        <span class="swup-progress-icon">-->
	<!--            <i class="fa-solid fa-circle-notch fa-spin"></i>-->
	<!--        </span>-->
	
</div>

<main class="page-container" id="swup">

	

	<div class="main-content-container flex flex-col justify-between min-h-dvh">
		<div class="main-content-header">
			<header class="navbar-container px-6 md:px-12">
    <div class="navbar-content transition-navbar ">
        <div class="left">
            
                <a class="logo-image h-8 w-8 sm:w-10 sm:h-10 mr-3" href="/">
                    <img src="/images/rabete.jpg" class="w-full h-full rounded-sm">
                </a>
            
            <a class="logo-title" href="/">
                
                xiaoeryu
                
            </a>
        </div>

        <div class="right">
            <!-- PC -->
            <div class="desktop">
                <ul class="navbar-list">
                    
                        
                            

                            <li class="navbar-item">
                                <!-- Menu -->
                                <a class=""
                                   href="/"
                                        >
                                    <i class="fa-regular fa-house fa-fw"></i>
                                    首页
                                    
                                </a>

                                <!-- Submenu -->
                                
                            </li>
                    
                        
                            

                            <li class="navbar-item">
                                <!-- Menu -->
                                <a class=""
                                   href="/archives"
                                        >
                                    <i class="fa-regular fa-archive fa-fw"></i>
                                    归档
                                    
                                </a>

                                <!-- Submenu -->
                                
                            </li>
                    
                    
                        <li class="navbar-item search search-popup-trigger">
                            <i class="fa-solid fa-magnifying-glass"></i>
                        </li>
                    
                </ul>
            </div>
            <!-- Mobile -->
            <div class="mobile">
                
                    <div class="icon-item search search-popup-trigger"><i class="fa-solid fa-magnifying-glass"></i>
                    </div>
                
                <div class="icon-item navbar-bar">
                    <div class="navbar-bar-middle"></div>
                </div>
            </div>
        </div>
    </div>

    <!-- Mobile sheet -->
    <div class="navbar-drawer h-dvh w-full absolute top-0 left-0 bg-background-color flex flex-col justify-between">
        <ul class="drawer-navbar-list flex flex-col px-4 justify-center items-start">
            
                
                    

                    <li class="drawer-navbar-item text-base my-1.5 flex flex-col w-full">
                        
                        <a class="py-1.5 px-2 flex flex-row items-center justify-between gap-1 hover:!text-primary active:!text-primary text-2xl font-semibold group border-b border-border-color hover:border-primary w-full "
                           href="/"
                        >
                            <span>
                                首页
                            </span>
                            
                                <i class="fa-regular fa-house fa-sm fa-fw"></i>
                            
                        </a>
                        

                        
                    </li>
            
                
                    

                    <li class="drawer-navbar-item text-base my-1.5 flex flex-col w-full">
                        
                        <a class="py-1.5 px-2 flex flex-row items-center justify-between gap-1 hover:!text-primary active:!text-primary text-2xl font-semibold group border-b border-border-color hover:border-primary w-full "
                           href="/archives"
                        >
                            <span>
                                归档
                            </span>
                            
                                <i class="fa-regular fa-archive fa-sm fa-fw"></i>
                            
                        </a>
                        

                        
                    </li>
            

            
            
        </ul>

        <div class="statistics flex justify-around my-2.5">
    <a class="item tag-count-item flex flex-col justify-center items-center w-20" href="/tags">
        <div class="number text-2xl sm:text-xl text-second-text-color font-semibold">92</div>
        <div class="label text-third-text-color text-sm">标签</div>
    </a>
    <a class="item tag-count-item flex flex-col justify-center items-center w-20" href="/categories">
        <div class="number text-2xl sm:text-xl text-second-text-color font-semibold">14</div>
        <div class="label text-third-text-color text-sm">分类</div>
    </a>
    <a class="item tag-count-item flex flex-col justify-center items-center w-20" href="/archives">
        <div class="number text-2xl sm:text-xl text-second-text-color font-semibold">112</div>
        <div class="label text-third-text-color text-sm">文章</div>
    </a>
</div>
    </div>

    <div class="window-mask"></div>

</header>


		</div>

		<div class="main-content-body transition-fade-up">
			

			<div class="main-content">
				<div class="post-page-container flex relative justify-between box-border w-full h-full">
	<div class="article-content-container">

		<div class="article-title relative w-full">
			
			<div class="w-full flex items-center pt-6 justify-start">
				<h1 class="article-title-regular text-second-text-color tracking-tight text-4xl md:text-6xl font-semibold px-2 sm:px-6 md:px-8 py-3">保护模式程序的动态加载和执行</h1>
			</div>
			
		</div>

		
		<div class="article-header flex flex-row gap-2 items-center px-2 sm:px-6 md:px-8">
			<div class="avatar w-[46px] h-[46px] flex-shrink-0 rounded-medium border border-border-color p-[1px]">
				<img src="/images/rabete.jpg">
			</div>
			<div class="info flex flex-col justify-between">
				<div class="author flex items-center">
					<span class="name text-default-text-color text-lg font-semibold">xiaoeryu</span>
					
					<span class="author-label ml-1.5 text-xs px-2 py-0.5 rounded-small text-third-text-color border border-shadow-color-1">Lv5</span>
					
				</div>
				<div class="meta-info">
					<div class="article-meta-info">
    <span class="article-date article-meta-item">
        <i class="fa-regular fa-pen-fancy"></i>&nbsp;
        <span class="desktop">2022-12-11 22:43</span>
        <span class="mobile">2022-12-11 22:43</span>
        <span class="hover-info">创建</span>
    </span>
    
        <span class="article-date article-meta-item">
            <i class="fa-regular fa-wrench"></i>&nbsp;
            <span class="desktop">2023-10-03 12:59:44</span>
            <span class="mobile">2023-10-03 12:59:44</span>
            <span class="hover-info">更新</span>
        </span>
    

    
        <span class="article-categories article-meta-item">
            <i class="fa-regular fa-folders"></i>&nbsp;
            <ul>
                
                
                    
                        
                        <li>
                            <a href="/categories/X86%E6%B1%87%E7%BC%96%EF%BC%9A%E5%AE%9E%E6%A8%A1%E5%BC%8F%E5%88%B0%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F/">X86汇编：实模式到保护模式</a>&nbsp;
                        </li>
                    
                    
                
            </ul>
        </span>
    
    
        <span class="article-tags article-meta-item">
            <i class="fa-regular fa-tags"></i>&nbsp;
            <ul>
                
                    <li>
                        <a href="/tags/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E4%B8%8B%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/">保护模式下的动态加载和执行</a>&nbsp;
                    </li>
                
            </ul>
        </span>
    

    
    
    
    
        <span class="article-pv article-meta-item">
            <i class="fa-regular fa-eye"></i>&nbsp;<span id="busuanzi_value_page_pv"></span>
        </span>
    
</div>

				</div>
			</div>
		</div>
		

		


		<div class="article-content markdown-body px-2 sm:px-6 md:px-8 pb-8">
			<h2 id="01-本章的目标和内容提要"><a href="#01-本章的目标和内容提要" class="headerlink" title="01. 本章的目标和内容提要"></a>01. 本章的目标和内容提要</h2><p>引入保护模式、描述符、描述符表等并没有对用户程序的编写增加什么负担</p>
<ul>
<li>因为对于系统来说这些是必须的，对于运行在系统上的程序来说不需要关心这些</li>
</ul>
<span id="more"></span>

<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/9bb28704b96ba84ebdd5cd6715a3c693.png" class="">

<h2 id="02-内核的结构和加载前的准备工作"><a href="#02-内核的结构和加载前的准备工作" class="headerlink" title="02. 内核的结构和加载前的准备工作"></a>02. 内核的结构和加载前的准备工作</h2><p>内核的加载包含<mark>c13_mbr.asm</mark>全部和<mark>c13_core. asm</mark>一小部分<br><strong>c13_mbr.asm</strong>用于：</p>
<ul>
<li>从BIOS中接管处理器以及硬件的控制权</li>
<li>安装最基本的段描述符</li>
<li>初始化最初的执行环境</li>
<li>然后从硬盘上读取和加载内核的剩余部分</li>
<li>创建组成内核的每一个内存段</li>
</ul>
<p><strong>c13_core.asm</strong>中定义的内核的分段信息：</p>
<ul>
<li>第一个分段：内核的头部，用于记录内核总长度，每个段的相对位置、以及入口点信息，以上统计信息用于告诉初始化代码如何加载内核；</li>
<li>第二个分段：公共例程段，本质上是一个代码段，包括一些可以反复使用的子过程，比如显示字符串例程、硬盘读写例程、内存分配例程、描述符创建和安装例程。这些子过程可以为内核自己使用也可以提供给用户程序使用；</li>
<li>第三个分段：数据段，包括系统核心数据，供内核自己使用；</li>
<li>第四个分段：代码段，包含进入内核之后首先要执行的代码、以及用于内存分配、读取和加载用户程序、控制用户程序的代码。</li>
</ul>
<h2 id="03-准备为内核的每个段创建和安装描述符"><a href="#03-准备为内核的每个段创建和安装描述符" class="headerlink" title="03. 准备为内核的每个段创建和安装描述符"></a>03. 准备为内核的每个段创建和安装描述符</h2><p>上一节中已经将内核全部读入内存， 这一节是找到内核的每一个段为他们创建并安装描述符。在保护模式下，内核访问自己的段也需要通过描述符。</p>
<p>内核的段描述符安装在<mark>GDT</mark>中，之前已经使用<mark>lgdt</mark>指令加载了<mark>GDTR</mark>，在这里我们就需要为<mark>GDT</mark>安装新的描述符。那我们的任务就是从标号<mark>pgdt</mark>处取得<mark>GDT</mark>的基地址，为其添加新的描述符，并修改新的界限值，之后使用<mark>lgdt</mark>指令再次加载<mark>GDTR</mark>使其生效。</p>
<p>但是，现在程序处于保护模式，对代码段的保护导致不能通过<mark>代码段描述符</mark>来修改代码段中的内容。但是可以使用占全部4G空间的数据段描述符（或者创建代码段的别名描述符）来修改与代码段重叠部分的内容。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/1fa11bf5789cca5df597cba02705eafa.png" class="">
<p>如图所示：大括号是4G字节的数据段、小括号是现在主引导程序所在的代码段，两个段有重叠的部分。</p>
<p>问：内核代码段的描述符还没有创建和安装，如何知道器选择子是什么？<br>答：内核常驻内存地址不会改变，内核在加载自己时会提前规划好每个段描述符的没醒，以及他们在描述符表中的位置，这样一来就知道每个段选择子的具体数值，因此为了方便可以将每个段的选择子定义为常数。<br>此时的内存布局：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/bb79369a945668586c907eff40be4df8.png" class="">

<h2 id="04-段描述符的创建和BSWAP指令"><a href="#04-段描述符的创建和BSWAP指令" class="headerlink" title="04. 段描述符的创建和BSWAP指令"></a>04. 段描述符的创建和BSWAP指令</h2><p>本节使用到的代码片段：<br><mark>c13_mbr.asm</mark></p>
<pre><code>setup:
         mov esi,[0x7c00+pgdt+0x02]         ;不可以在代码段内寻址pgdt，但可以
                                            ;通过4GB的段来访问
         ;建立公用例程段描述符
         mov eax,[edi+0x04]                 ;公用例程代码段起始汇编地址
         mov ebx,[edi+0x08]                 ;核心数据段汇编地址
         sub ebx,eax
         dec ebx                            ;公用例程段界限 
         add eax,edi                        ;公用例程段基地址
         mov ecx,0x00409800                 ;字节粒度的代码段描述符
         call make_gdt_descriptor
         mov [esi+0x28],eax
         mov [esi+0x2c],edx 
</code></pre>
<p><mark>c13_core.asm</mark></p>
<pre><code>make_seg_descriptor:                        ;构造存储器和系统的段描述符
                                            ;输入：EAX=线性基地址
                                            ;      EBX=段界限
                                            ;      ECX=属性。各属性位都在原始
                                            ;          位置，无关的位清零 
                                            ;返回：EDX:EAX=描述符
         mov edx,eax
         shl eax,16
         or ax,bx                           ;描述符前32位(EAX)构造完毕

         and edx,0xffff0000                 ;清除基地址中无关的位
         rol edx,8
         bswap edx                          ;装配基址的31~24和23~16  (80486+)

         xor bx,bx
         or edx,ebx                         ;装配段界限的高4位

         or edx,ecx                         ;装配属性

         retf 
</code></pre>
<p>内存布局如下，使用的是4G字节的数据段从0开始，那么公共例程段的逻辑地址就等于<mark>EDI</mark>指定的地址。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/b0486969de5d713ba29775fe980d06fd.png" class="">

<p>使用<mark>make_gdt_descriptor</mark>子程序构造描述符的低32位：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/72752de04c5902657684c80fe03e60d4.png" class="">

<p>高32位的基地址部分：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/53951340edc787f76dad35ab5b8028c6.png" class="">

<p>数据反转指令：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/8e19731756b24be358680fb326a7e15d.png" class="">

<p>将32位寄存器分成四个八位头尾反转，中间相邻反转：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/07bfd474ab406622ec6744724c74846d.png" class="">

<p>高32位的<mark>段界限</mark>部分：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/ca7c9e31c5f3d321a4ea2243ef708dac.png" class="">


<h2 id="05-进入内核执行"><a href="#05-进入内核执行" class="headerlink" title="05. 进入内核执行"></a>05. 进入内核执行</h2><p>本节用到的代码片段：</p>
<pre><code>         ;建立核心数据段描述符
         mov eax,[edi+0x08]                 ;核心数据段起始汇编地址
         mov ebx,[edi+0x0c]                 ;核心代码段汇编地址 
         sub ebx,eax
         dec ebx                            ;核心数据段界限
         add eax,edi                        ;核心数据段基地址
         mov ecx,0x00409200                 ;字节粒度的数据段描述符 
         call make_gdt_descriptor
         mov [esi+0x30],eax
         mov [esi+0x34],edx 
      
         ;建立核心代码段描述符
         mov eax,[edi+0x0c]                 ;核心代码段起始汇编地址
         mov ebx,[edi+0x00]                 ;程序总长度
         sub ebx,eax
         dec ebx                            ;核心代码段界限
         add eax,edi                        ;核心代码段基地址
         mov ecx,0x00409800                 ;字节粒度的代码段描述符
         call make_gdt_descriptor
         mov [esi+0x38],eax
         mov [esi+0x3c],edx

         mov word [0x7c00+pgdt],63          ;描述符表的界限
                                        
         lgdt [0x7c00+pgdt]                  

         jmp far [edi+0x10]
</code></pre>
<p>内核加载之后的<mark>GDT</mark>布局：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/24a4d1969cb1dce52429158938f30178.png" class="">

<p>4G字节字段内存布局：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/06ac92012b3feaf193f6590e8e96669e.png" class="">
<p>执行<mark>jmp far[edi+0x10]</mark> 指令时：处理器使用 <mark>DS描述符高速缓存器中的基地址0</mark> 加上 <mark>[edi+0x10]生成的有效偏移地址</mark> 得到内存中的线性地址去访问内存取出<font color="#00ffff" size="3">32位段内偏移</font>和 <mark>16位段选择子</mark>，然后用<mark>段选择子</mark>到<mark>GDT</mark>中取出对应的<mark>段描述符</mark>在经过检查后放入<mark>CS描述符高速缓存器</mark>中，同时将<font color="#00ffff" size="3">32位段内偏移</font>传送到<font color="#00ffff" size="3">EIP</font>，之后处理器使用<mark>CS描述符高速缓存器</mark>中的<mark>段基地址</mark>加上<font color="#00ffff" size="3">EIP</font>中的偏移作为逻辑地址去执行指令，即到内核入口点取指令并执行。</p>
<h2 id="06-进入内核之后显示文本"><a href="#06-进入内核之后显示文本" class="headerlink" title="06. 进入内核之后显示文本"></a>06. 进入内核之后显示文本</h2><p>进入内核之后显示文本信息，本节代码：</p>
<pre><code>SECTION sys_routine vstart=0                ;系统公共例程代码段 
;-------------------------------------------------------------------------------
         ;字符串显示例程
put_string:                                 ;显示0终止的字符串并移动光标 
                                            ;输入：DS:EBX=串地址
         push ecx
  .getc:
         mov cl,[ebx]
         or cl,cl
         jz .exit
         call put_char
         inc ebx
         jmp .getc

  .exit:
         pop ecx
         retf                               ;段间返回

;-------------------------------------------------------------------------------
put_char:                                   ;在当前光标处显示一个字符,并推进
                                            ;光标。仅用于段内调用 
                                            ;输入：CL=字符ASCII码 
         pushad

         ;以下取当前光标位置
         mov dx,0x3d4
         mov al,0x0e
         out dx,al
         inc dx                             ;0x3d5
         in al,dx                           ;高字
         mov ah,al

         dec dx                             ;0x3d4
         mov al,0x0f
         out dx,al
         inc dx                             ;0x3d5
         in al,dx                           ;低字
         mov bx,ax                          ;BX=代表光标位置的16位数

         cmp cl,0x0d                        ;回车符？
         jnz .put_0a
         mov ax,bx
         mov bl,80
         div bl
         mul bl
         mov bx,ax
         jmp .set_cursor

  .put_0a:
         cmp cl,0x0a                        ;换行符？
         jnz .put_other
         add bx,80
         jmp .roll_screen

  .put_other:                               ;正常显示字符
         push es
         mov eax,video_ram_seg_sel          ;0xb8000段的选择子
         mov es,eax
         shl bx,1
         mov [es:bx],cl
         pop es

         ;以下将光标位置推进一个字符
         shr bx,1
         inc bx

  .roll_screen:
         cmp bx,2000                        ;光标超出屏幕？滚屏
         jl .set_cursor

         push ds
         push es
         mov eax,video_ram_seg_sel
         mov ds,eax
         mov es,eax
         cld
         mov esi,0xa0                       ;小心！32位模式下movsb/w/d 
         mov edi,0x00                       ;使用的是esi/edi/ecx 
         mov ecx,1920
         rep movsd
         mov bx,3840                        ;清除屏幕最底一行
         mov ecx,80                         ;32位程序应该使用ECX
  .cls:
         mov word[es:bx],0x0720
         add bx,2
         loop .cls

         pop es
         pop ds

         mov bx,1920

  .set_cursor:
         mov dx,0x3d4
         mov al,0x0e
         out dx,al
         inc dx                             ;0x3d5
         mov al,bh
         out dx,al
         dec dx                             ;0x3d4
         mov al,0x0f
         out dx,al
         inc dx                             ;0x3d5
         mov al,bl
         out dx,al

         popad
         ret   
</code></pre>
<pre><code>start:
         mov ecx,core_data_seg_sel           ;使ds指向核心数据段 
         mov ds,ecx

         mov ebx,message_1
         call sys_routine_seg_sel:put_string 
</code></pre>
<p>进入<mark>start</mark>标号之后，先将内核自己的数据段选择子<mark>core_data_seg_sel</mark>传送给<mark>DS</mark>，之后将文本信息的标号<mark>message_1</mark>传送给<mark>ebx</mark>，之后使用<mark>call</mark>指令进行过程调用，处理器将段寄存器<mark>CS</mark>和指令指针寄存器<mark>EIP(下一条指令的有效地址)</mark>进行压栈保存，使用指令中的系统公共例程代码段的选择子<mark>sys_routine_seg_sel</mark>取得描述符，经过检查之后加载到<mark>CS描述符高速缓存器</mark>，同时使用指令中的偏移量<mark>put_string</mark>改变指令指针寄存器<mark>EIP</mark>，这样就转到目标过程内部执行。</p>
<p>其中<mark>movsd</mark>指令的操作和当前默认操作尺寸相关：<br>    1. 当前操作尺寸是16位，源操作数由<mark>DS:SI</mark>指定、目的操作数由<mark>ES:DI</mark>指定；<br>    2. 当前操作尺寸是32位，源操作数由<mark>DS:ESI</mark>指定、目的操作数由<mark>ES:EDI</mark>指定；<br>    且由于当前是在32位操作尺寸下，所以重复传送的次数由<mark>ECX</mark>指定。</p>
<h2 id="07-用CPUID指令显示处理器品牌信息并显示"><a href="#07-用CPUID指令显示处理器品牌信息并显示" class="headerlink" title="07. 用CPUID指令显示处理器品牌信息并显示"></a>07. 用CPUID指令显示处理器品牌信息并显示</h2><p><mark>cpuid(CPU identification)</mark>指令用于返回处理器的标识和特性信息，需要使用<mark>EAX</mark>指定要返回什么样的信息，指定功能号。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/cced9754233b346a0965ffc53d66187c.png" class="">

<p><mark>cpuid</mark>指令是在<mark>80486</mark>后期版本引入，在执行<mark>cpuid</mark>指令之前要检测处理器是否支持该指令：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/5e72268ea5185704e17458c5ff490729.png" class="">
<p><mark>EFLAGS</mark>的位21是ID位，为0表示不支持cpuid指令，为1表示支持cpuid指令<br>本节代码：</p>
<pre><code class="assembly">         cpu_brnd0        db 0x0d,0x0a,'  ',0
         cpu_brand  times 52 db 0
         cpu_brnd1        db 0x0d,0x0a,0x0d,0x0a,0
</code></pre>
<pre><code class="assembly">                        ;显示处理器品牌信息 
         mov eax,0x80000002
         cpuid
         mov [cpu_brand + 0x00],eax
         mov [cpu_brand + 0x04],ebx
         mov [cpu_brand + 0x08],ecx
         mov [cpu_brand + 0x0c],edx
      
         mov eax,0x80000003
         cpuid
         mov [cpu_brand + 0x10],eax
         mov [cpu_brand + 0x14],ebx
         mov [cpu_brand + 0x18],ecx
         mov [cpu_brand + 0x1c],edx

         mov eax,0x80000004
         cpuid
         mov [cpu_brand + 0x20],eax
         mov [cpu_brand + 0x24],ebx
         mov [cpu_brand + 0x28],ecx
         mov [cpu_brand + 0x2c],edx

         mov ebx,cpu_brnd0
         call sys_routine_seg_sel:put_string
         mov ebx,cpu_brand
         call sys_routine_seg_sel:put_string
         mov ebx,cpu_brnd1
         call sys_routine_seg_sel:put_string 
</code></pre>
<h2 id="08-准备加载用户程序"><a href="#08-准备加载用户程序" class="headerlink" title="08. 准备加载用户程序"></a>08. 准备加载用户程序</h2><p>接上一节，加载用户程序：</p>
<pre><code class="assembly">         mov ebx,message_5
         call sys_routine_seg_sel:put_string
         mov esi,50                          ;用户程序位于逻辑50扇区 
         call load_relocate_program
</code></pre>
<pre><code class="assembly">SECTION header vstart=0

         program_length   dd program_end          ;程序总长度#0x00
         
         head_len         dd header_end           ;程序头部的长度#0x04

         stack_seg        dd 0                    ;用于接收堆栈段选择子#0x08
         stack_len        dd 1                    ;程序建议的堆栈大小#0x0c
                                                  ;以4KB为单位
                                                  
         prgentry         dd start                ;程序入口#0x10 
         code_seg         dd section.code.start   ;代码段位置#0x14
         code_len         dd code_end             ;代码段长度#0x18

         data_seg         dd section.data.start   ;数据段位置#0x1c
         data_len         dd data_end             ;数据段长度#0x20 
</code></pre>
<p>主要讲了用户程序的构造，由哪些部分组成起始和结束地址在哪，具体代码看c13.asm</p>
<h2 id="09-预读用户程序并得到它的大小"><a href="#09-预读用户程序并得到它的大小" class="headerlink" title="09. 预读用户程序并得到它的大小"></a>09. 预读用户程序并得到它的大小</h2><p>内容：读取用户程序的第一个扇区，取得用户程序的长度</p>
<pre><code class="assembly">SECTION core_code vstart=0
;-------------------------------------------------------------------------------
load_relocate_program:                      ;加载并重定位用户程序
                                            ;输入：ESI=起始逻辑扇区号
                                            ;返回：AX=指向用户程序头部的选择子 
         push ebx
         push ecx
         push edx
         push esi
         push edi
      
         push ds
         push es
      
         mov eax,core_data_seg_sel
         mov ds,eax                         ;切换DS到内核数据段
       
         mov eax,esi                        ;读取程序头部数据 
         mov ebx,core_buf                        
         call sys_routine_seg_sel:read_hard_disk_0 
</code></pre>
<h2 id="10-条件传送簇CMOVcc"><a href="#10-条件传送簇CMOVcc" class="headerlink" title="10. 条件传送簇CMOVcc"></a>10. 条件传送簇CMOVcc</h2><p><mark>mov</mark>指令传统方式：会影响流水线效率，因为条件转移指令发生就会使流水线编译的译码失效需要重新编译，虽然现代处理器有了分支预测技术但是分支预测并不总是对的。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/0d699825616fb370b99fdac1f9689859.png" class="">

<p>使用<mark>CMOVcc</mark>指令简化传送指令：<mark>ne</mark>表示<mark>Not Equal</mark></p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/a37067392ac8d6dba19b384c333b109c.png" class="">

<p>Intel手册中有<mark>CMOV</mark>指令文档</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/0b088096f037a5b3383b83b003e3ca11.png" class="">

<p><mark>CMOV</mark>指令格式</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/0671b8c5bff812d609716ade0c2bd572.png" class="">

<p>条件传送指令是从<mark>P6处理器</mark>开始引入的，使用<mark>1</mark>功能号通过查看<mark>EDX</mark>的返回值可以查看处理器是否支持这个指令簇</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/826acaeec0d57740394d8a9bb0052db9.png" class="">


<h2 id="11-计算以512字节为单位的用户程序总长度"><a href="#11-计算以512字节为单位的用户程序总长度" class="headerlink" title="11. 计算以512字节为单位的用户程序总长度"></a>11. 计算以512字节为单位的用户程序总长度</h2><p>在二进制中，512整数倍的数，低9位均为0。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/4dfe3bf8b2ce32811fa15da1fe42f3a5.png" class="">

<p>判断用户程序的大小是否为<mark>512</mark>的整倍数</p>
<pre><code class="assembly">         ;以下判断整个程序有多大
         mov eax,[core_buf]                 ;程序尺寸
         mov ebx,eax
         and ebx,0xfffffe00                 ;使之512字节对齐（能被512整除的数， 
         add ebx,512                        ;低9位都为0 
         test eax,0x000001ff                ;程序的大小正好是512的倍数吗? 
         cmovnz eax,ebx                     ;不是。使用凑整的结果 
</code></pre>
<h2 id="12-内存分配的基本策略和方法"><a href="#12-内存分配的基本策略和方法" class="headerlink" title="12. 内存分配的基本策略和方法"></a>12. 内存分配的基本策略和方法</h2><p> 操作系统必须记录所有可以分配的物理内存，当一个程序要求分配内存时，内存管理程序从可分配的内存中切割出一段将其标记为已使用。已分配内存在使用之后还需要负责回收它们，将其标记为空闲以便再次分配。</p>
<p> 当内存空间紧张时，内存管理程序还需要查找那些很久未使用的程序，将其移出到硬盘上，腾出空间给需要使用内存的程序使用。下次用到这些内存时再将其加载到内存中。这就是<mark>虚拟内存管理</mark>。</p>
<p> 现在的内存布局：<br> <img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/4e008d4175628203a066130d057cce66.png" class=""></p>
<p> 若一次分配<mark>512</mark>字节内存，从<mark>0x00100000</mark>处开始分配，则下一次从<mark>0x00100200</mark>处开始继续分配。<br> <img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/04ac4b9bbf72aa3bf7d650f4b83b071f.png" class=""></p>
<h2 id="13-内存分配的简易实现过程"><a href="#13-内存分配的简易实现过程" class="headerlink" title="13. 内存分配的简易实现过程"></a>13. 内存分配的简易实现过程</h2><p> 本节代码：</p>
<pre><code class="assembly">allocate_memory:                            ;分配内存
                                           ;输入：ECX=希望分配的字节数
                                           ;输出：ECX=起始线性地址 
        push ds
        push eax
        push ebx
     
        mov eax,core_data_seg_sel
        mov ds,eax
     
        mov eax,[ram_alloc]
        add eax,ecx                        ;下一次分配时的起始地址
     
        ;这里应当有检测可用内存数量的指令
         
        mov ecx,[ram_alloc]                ;返回分配的起始地址

        mov ebx,eax
        and ebx,0xfffffffc
        add ebx,4                          ;强制对齐 
        test eax,0x00000003                ;下次分配的起始地址最好是4字节对齐
        cmovnz eax,ebx                     ;如果没有对齐，则强制对齐 
        mov [ram_alloc],eax                ;下次从该地址分配内存
                                           ;cmovcc指令可以避免控制转移 
        pop ebx
        pop eax
        pop ds

        retf             
</code></pre>
<h2 id="14-加载用户程序"><a href="#14-加载用户程序" class="headerlink" title="14. 加载用户程序"></a>14. 加载用户程序</h2><p> 本节代码：</p>
<pre><code class="assembly">         mov ecx,eax                        ;实际需要申请的内存数量
        call sys_routine_seg_sel:allocate_memory
        mov ebx,ecx                        ;ebx -&gt; 申请到的内存首地址
        push ebx                           ;保存该首地址 
        xor edx,edx
        mov ecx,512
        div ecx
        mov ecx,eax                        ;总扇区数 
     
        mov eax,mem_0_4_gb_seg_sel         ;切换DS到0-4GB的段
        mov ds,eax

        mov eax,esi                        ;起始扇区号 
 .b1:
        call sys_routine_seg_sel:read_hard_disk_0
        inc eax
        loop .b1
</code></pre>
<h2 id="15-准备安装用户程序的段描述符"><a href="#15-准备安装用户程序的段描述符" class="headerlink" title="15. 准备安装用户程序的段描述符"></a>15. 准备安装用户程序的段描述符</h2><p> 本节代码：</p>
<pre><code class="assembly">        ;建立程序头部段描述符
       pop edi                            ;恢复程序装载的首地址 
       mov eax,edi                        ;程序头部起始线性地址
       mov ebx,[edi+0x04]                 ;段长度
       dec ebx                            ;段界限 
       mov ecx,0x00409200                 ;字节粒度的数据段描述符
       call sys_routine_seg_sel:make_seg_descriptor
       call sys_routine_seg_sel:set_up_gdt_descriptor
       mov [edi+0x04],cx 
</code></pre>
<p>使用<mark>make-seg_descriptor</mark>创建描述符、使用<mark>set_up_gdt_descriptor</mark>安装描述符。</p>
<p>其中头部段描述符：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/144616b2a2b154bd174b8d71383ff689.png" class="">

<ul>
<li>G位：0表示段界限以字节为单位</li>
<li>P位：1表示段存在</li>
<li>S位：1表示这是一个存储器的段描述符</li>
<li>X位：0表示这是一个数据段</li>
<li>E位：0表示段向上扩展</li>
<li>W位：0表示可读可写</li>
</ul>
<h2 id="16-用SGDT和MOVZX指令确定GDT的位置"><a href="#16-用SGDT和MOVZX指令确定GDT的位置" class="headerlink" title="16. 用SGDT和MOVZX指令确定GDT的位置"></a>16. 用SGDT和MOVZX指令确定GDT的位置</h2><p><mark>sgdt m</mark>指令：将<mark>GDTR</mark>的内容保存到内存地址<mark>m</mark>处</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/8ee964a20a641a57cd2df08e5c65c163.png" class="">

<p><mark>movzx</mark>指令：0扩展传送指令</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/a7b3bddccde1412511d349b08ec6851b.png" class="">
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/894b778c290e658fb31380b2feab024e.png" class="">

<p><mark>movsx</mark>：符号位扩展传送指令</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/87fd4f6a3c17dfc49006dfa49461fa5e.png" class="">
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/0c0ba9317c35169c418216cb17d82d0c.png" class="">

<p>本节代码：<mark>GDTR</mark>是一个<mark>48</mark>位的寄存器高<mark>32</mark>位存储的内容是<mark>GDT起始线性地址</mark>低<mark>16</mark>位存储的内容是<mark>GDT的界限值</mark>，通过sgdt指令获取到GDTR的值之后提取低16位的界限值将<mark>界限值加1</mark>再加上<mark>GDT的起始线性地址</mark>即可得到下一个描述符的线性地址，后面就可以使用这个线性地址来安装新的描述符。</p>
<pre><code class="assembly">set_up_gdt_descriptor:                      ;在GDT内安装一个新的描述符
                                            ;输入：EDX:EAX=描述符 
                                            ;输出：CX=描述符的选择子
         push eax
         push ebx
         push edx
      
         push ds
         push es
      
         mov ebx,core_data_seg_sel          ;切换到核心数据段
         mov ds,ebx

         sgdt [pgdt]                        ;以便开始处理GDT

         mov ebx,mem_0_4_gb_seg_sel
         mov es,ebx

         movzx ebx,word [pgdt]              ;GDT界限 
         inc bx                             ;GDT总字节数，也是下一个描述符偏移 
         add ebx,[pgdt+2]                   ;下一个描述符的线性地址 
      
</code></pre>
<h2 id="17-安装新描述符并生成选择子"><a href="#17-安装新描述符并生成选择子" class="headerlink" title="17. 安装新描述符并生成选择子"></a>17. 安装新描述符并生成选择子</h2><p>接上一节代码：</p>
<pre><code class="assembly">         mov [es:ebx],eax
         mov [es:ebx+4],edx
      
         add word [pgdt],8                  ;增加一个描述符的大小   
      
         lgdt [pgdt]                        ;对GDT的更改生效 
       
         mov ax,[pgdt]                      ;得到GDT界限值
         xor dx,dx
         mov bx,8
         div bx                             ;除以8，去掉余数
         mov cx,ax                          
         shl cx,3                           ;将索引号移到正确位置 

         pop es
         pop ds

         pop edx
         pop ebx
         pop eax
      
         retf 
</code></pre>
<p>安装了新的描述符之后使用<mark>lgdt[pgdt]</mark>指令使得新的描述符生效，然后将GDT的界限值除以8得到描述符的索引号，再将索引号左移三位右边补零生成新的选择子。</p>
<h2 id="18-安装用户程序的段描述符并回填选择子"><a href="#18-安装用户程序的段描述符并回填选择子" class="headerlink" title="18. 安装用户程序的段描述符并回填选择子"></a>18. 安装用户程序的段描述符并回填选择子</h2><p>代码如下：</p>
<pre><code class="assembly">;建立程序头部段描述符
         pop edi                            ;恢复程序装载的首地址 
         mov eax,edi                        ;程序头部起始线性地址
         mov ebx,[edi+0x04]                 ;段长度
         dec ebx                            ;段界限 
         mov ecx,0x00409200                 ;字节粒度的数据段描述符
         call sys_routine_seg_sel:make_seg_descriptor
         call sys_routine_seg_sel:set_up_gdt_descriptor
         mov [edi+0x04],cx               
</code></pre>
<p>回填选择子：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/99972661419e171cf0c3cdaaafd94d1f.png" class="">

<p>之后用户程序头部的<mark>0x04</mark>处就是<mark>选择子</mark>了，而且只用到了低32位，高32位还是原来的值</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/6d34a115a6fee41642876058aa070a2c.png" class="">

<p>接着创建代码段描述符：</p>
<pre><code class="assembly">         ;建立程序代码段描述符
         mov eax,edi
         add eax,[edi+0x0c]                 ;代码起始线性地址
         mov ebx,[edi+0x10]                 ;段长度
         dec ebx                            ;段界限
         mov ecx,0x00409800                 ;字节粒度的代码段描述符
         call sys_routine_seg_sel:make_seg_descriptor
         call sys_routine_seg_sel:set_up_gdt_descriptor
         mov [edi+0x14],cx   
</code></pre>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/e38333b91447d2184bcae4ae6b518ed4.png" class="">
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/90d787418a73c3b0e54694974514c50a.png" class="">

<p>之后就进行安装和加载描述符，后面还有数据段和栈段描述符：流程基本都是一样的</p>
<pre><code class="assembly"> ;建立程序数据段描述符
         mov eax,edi
         add eax,[edi+0x14]                 ;数据段起始线性地址
         mov ebx,[edi+0x18]                 ;段长度
         dec ebx                            ;段界限
         mov ecx,0x00409200                 ;字节粒度的数据段描述符
         call sys_routine_seg_sel:make_seg_descriptor
         call sys_routine_seg_sel:set_up_gdt_descriptor
         mov [edi+0x14],cx

 ;建立程序堆栈段描述符      
        mov eax,edi
        add eax,[edi+0x1c]					;栈段起始线性地址
        mov ebx,[edi+0x20]					;段长度
        dec ebx								;段界限
        mov ecx,0x00409200					；字节粒度的数据段描述符
        call sys_routine_seg_sel:make_seg_descriptor
        call sys_routine_seg_sel:set_up_gdt_descriptor
        mov [edi+0x1c],cx
</code></pre>
<h2 id="19-用户程序的执行和退出"><a href="#19-用户程序的执行和退出" class="headerlink" title="19. 用户程序的执行和退出"></a>19. 用户程序的执行和退出</h2><p>从<mark>load_relocate_program</mark>程序返回之前将用户程序头部段的选择子保存在<mark>AX</mark>中。</p>
<pre><code class="assembly">SECTION core_code vstart=0
;-------------------------------------------------------------------------------
load_relocate_program:                      ;加载并重定位用户程序
                                            ;输入：ESI=起始逻辑扇区号
                                            ;返回：AX=指向用户程序头部的选择子 
         push ebx
         push ecx
         push edx
         push esi
         push edi
      
         push ds
         push es
      
         mov eax,core_data_seg_sel
         mov ds,eax                         ;切换DS到内核数据段
       
         mov eax,esi                        ;读取程序头部数据 
         mov ebx,core_buf                        
         call sys_routine_seg_sel:read_hard_disk_0       
         
         ...
         ...
         ...
         
         mov ax,[es:0x04]

         pop es                             ;恢复到调用此过程前的es段 
         pop ds                             ;恢复到调用此过程前的ds段
      
         pop edi
         pop esi
         pop edx
         pop ecx
         pop ebx
      
         ret        
</code></pre>
<p>从<mark>load_relocate_program</mark>程序返回内核程序：</p>
<pre><code class="assembly">          call load_relocate_program
         mov ebx,do_status
         call sys_routine_seg_sel:put_string
      
         mov [esp_pointer],esp               ;临时保存堆栈指针
       
         mov ds,ax							 ;从load_relocate_program程序返回时，用户程序头部段选择子存在AX中

         call far [0x08]                     ;控制权交给用户程序（入口点）
                                             ;堆栈可能切换 
</code></pre>
<p>这条<mark>call far [0x08]</mark> 指令执行时，处理器用段寄存器<mark>DS</mark>访问用户程序头部段，从偏移为8的地方取出32位偏移量传送到指令指针<mark>EIP</mark>，再取出16位段选择子传送到段寄存器<mark>DS</mark>，然后处理器进入用户程序内部执行。<br>用户程序<mark>start</mark>代码：</p>
<pre><code class="assembly">SECTION code vstart=0

start:
         mov eax,ds		;此时DS指向用户程序头部段
         mov fs,eax		;但是我们不能失去对DS的追踪，所以使用其他FS段寄存器重新设置DS

         ;mov eax,[stack_seg]
         ;mov ss,eax
         ;mov esp,stack_end

         ;mov eax,[data_seg]
         ;mov ds,eax

         ;用户程序要做的事情（省略）

         retf                                     ;将控制权返回到系统

code_end:
</code></pre>
<p>从用户程序返回到内核代码段：</p>
<pre><code class="assembly">    call far [0x08]                     ;控制权交给用户程序（入口点）
                                        ;堆栈可能切换 
    
return_point:                           ;用户程序返回点
    mov eax,core_data_seg_sel           ;使ds指向核心数据段
    mov ds,eax
    
    mov eax,core_stack_seg_sel          ;切换回内核自己的堆栈
    mov ss,eax 
    mov esp,[esp_pointer]
    
    mov ebx,message_6
    call sys_routine_seg_sel:put_string
    
    ;这里可以放置清除用户程序各种描述符的指令
    ;也可以加载并启动其它程序
    
    hlt	;在主引导程序进入保护模式之前使用cli指令清除了中断，
        ;所以在这里用hlt指令让处理器停机之后不会被中断唤醒
</code></pre>
<h2 id="20-在虚拟机上观察内核的加载以及用户程序的执行与推出"><a href="#20-在虚拟机上观察内核的加载以及用户程序的执行与推出" class="headerlink" title="20. 在虚拟机上观察内核的加载以及用户程序的执行与推出"></a>20. 在虚拟机上观察内核的加载以及用户程序的执行与推出</h2><p>起始LBA扇区号：</p>
<ul>
<li>主引导程序：0</li>
<li>内核程序：1</li>
<li>用户程序：50</li>
</ul>
<p>VirtualBox虚拟机执行成功：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/196c7eb008b6f6764d38d54857bbfa46.png" class="">

<p>Bochs虚拟机执行成功：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/25-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/0df1110c1d014a7245f3fcb33df9f078.png" class="">

<p>可以自行调试观察<mark>EFLAGS、GDT、内核程序头部和用户程序头部</mark>内容以及栈的变化。</p>

		</div>

		
		<div class="post-copyright-info w-full my-8 px-2 sm:px-6 md:px-8">
			<div class="article-copyright-info-container">
    <ul>
        <li><strong>标题:</strong> 保护模式程序的动态加载和执行</li>
        <li><strong>作者:</strong> xiaoeryu</li>
        <li><strong>创建于
                :</strong> 2022-12-11 22:43:00</li>
        
            <li>
                <strong>更新于
                    :</strong> 2023-10-03 12:59:44
            </li>
        
        <li>
            <strong>链接:</strong> https://github.com/xiaoeryu/2022/12/11/25-保护模式程序的动态加载和执行/
        </li>
        <li>
            <strong>
                版权声明:
            </strong>
            

            
                本文章采用 <a class="license" target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0">CC BY-NC-SA 4.0</a> 进行许可。
            
        </li>
    </ul>
</div>

		</div>
		

		
		<ul class="post-tags-box text-lg mt-1.5 flex-wrap justify-center flex md:hidden">
			
			<li class="tag-item mx-0.5">
				<a href="/tags/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E4%B8%8B%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%89%A7%E8%A1%8C/">#保护模式下的动态加载和执行</a>&nbsp;
			</li>
			
		</ul>
		

		

		
		<div class="article-nav my-8 flex justify-between items-center px-2 sm:px-6 md:px-8">
			
			<div class="article-prev border-border-color shadow-redefine-flat shadow-shadow-color-2 rounded-medium px-4 py-2 hover:shadow-redefine-flat-hover hover:shadow-shadow-color-2">
				<a class="prev" rel="prev" href="/2022/12/11/26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0/">
					<span class="left arrow-icon flex justify-center items-center">
						<i class="fa-solid fa-chevron-left"></i>
					</span>
					<span class="title flex justify-center items-center">
						<span class="post-nav-title-item">用户程序编程接口及其实现</span>
						<span class="post-nav-item">上一篇</span>
					</span>
				</a>
			</div>
			
			
			<div class="article-next border-border-color shadow-redefine-flat shadow-shadow-color-2 rounded-medium px-4 py-2 hover:shadow-redefine-flat-hover hover:shadow-shadow-color-2">
				<a class="next" rel="next" href="/2022/12/11/24-%E5%AD%98%E5%82%A8%E5%99%A8%E7%9A%84%E4%BF%9D%E6%8A%A4/">
					<span class="title flex justify-center items-center">
						<span class="post-nav-title-item">存储器的保护</span>
						<span class="post-nav-item">下一篇</span>
					</span>
					<span class="right arrow-icon flex justify-center items-center">
						<i class="fa-solid fa-chevron-right"></i>
					</span>
				</a>
			</div>
			
		</div>
		


		
		<div class="comment-container px-2 sm:px-6 md:px-8 pb-8">
			<div class="comments-container mt-10 w-full ">
    <div id="comment-anchor" class="w-full h-2.5"></div>
    <div class="comment-area-title w-full my-1.5 md:my-2.5 text-xl md:text-3xl font-bold">
        评论
    </div>
    

        
            


        
    
</div>

		</div>
		
	</div>

	
	<div class="toc-content-container">
		<div class="post-toc-wrap">
	<div class="post-toc">
		<div class="toc-title">目录</div>
		<div class="page-title">保护模式程序的动态加载和执行</div>
		<ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#01-%E6%9C%AC%E7%AB%A0%E7%9A%84%E7%9B%AE%E6%A0%87%E5%92%8C%E5%86%85%E5%AE%B9%E6%8F%90%E8%A6%81"><span class="nav-text">01. 本章的目标和内容提要</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#02-%E5%86%85%E6%A0%B8%E7%9A%84%E7%BB%93%E6%9E%84%E5%92%8C%E5%8A%A0%E8%BD%BD%E5%89%8D%E7%9A%84%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C"><span class="nav-text">02. 内核的结构和加载前的准备工作</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#03-%E5%87%86%E5%A4%87%E4%B8%BA%E5%86%85%E6%A0%B8%E7%9A%84%E6%AF%8F%E4%B8%AA%E6%AE%B5%E5%88%9B%E5%BB%BA%E5%92%8C%E5%AE%89%E8%A3%85%E6%8F%8F%E8%BF%B0%E7%AC%A6"><span class="nav-text">03. 准备为内核的每个段创建和安装描述符</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#04-%E6%AE%B5%E6%8F%8F%E8%BF%B0%E7%AC%A6%E7%9A%84%E5%88%9B%E5%BB%BA%E5%92%8CBSWAP%E6%8C%87%E4%BB%A4"><span class="nav-text">04. 段描述符的创建和BSWAP指令</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#05-%E8%BF%9B%E5%85%A5%E5%86%85%E6%A0%B8%E6%89%A7%E8%A1%8C"><span class="nav-text">05. 进入内核执行</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#06-%E8%BF%9B%E5%85%A5%E5%86%85%E6%A0%B8%E4%B9%8B%E5%90%8E%E6%98%BE%E7%A4%BA%E6%96%87%E6%9C%AC"><span class="nav-text">06. 进入内核之后显示文本</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#07-%E7%94%A8CPUID%E6%8C%87%E4%BB%A4%E6%98%BE%E7%A4%BA%E5%A4%84%E7%90%86%E5%99%A8%E5%93%81%E7%89%8C%E4%BF%A1%E6%81%AF%E5%B9%B6%E6%98%BE%E7%A4%BA"><span class="nav-text">07. 用CPUID指令显示处理器品牌信息并显示</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#08-%E5%87%86%E5%A4%87%E5%8A%A0%E8%BD%BD%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F"><span class="nav-text">08. 准备加载用户程序</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#09-%E9%A2%84%E8%AF%BB%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E5%B9%B6%E5%BE%97%E5%88%B0%E5%AE%83%E7%9A%84%E5%A4%A7%E5%B0%8F"><span class="nav-text">09. 预读用户程序并得到它的大小</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#10-%E6%9D%A1%E4%BB%B6%E4%BC%A0%E9%80%81%E7%B0%87CMOVcc"><span class="nav-text">10. 条件传送簇CMOVcc</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#11-%E8%AE%A1%E7%AE%97%E4%BB%A5512%E5%AD%97%E8%8A%82%E4%B8%BA%E5%8D%95%E4%BD%8D%E7%9A%84%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E6%80%BB%E9%95%BF%E5%BA%A6"><span class="nav-text">11. 计算以512字节为单位的用户程序总长度</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#12-%E5%86%85%E5%AD%98%E5%88%86%E9%85%8D%E7%9A%84%E5%9F%BA%E6%9C%AC%E7%AD%96%E7%95%A5%E5%92%8C%E6%96%B9%E6%B3%95"><span class="nav-text">12. 内存分配的基本策略和方法</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#13-%E5%86%85%E5%AD%98%E5%88%86%E9%85%8D%E7%9A%84%E7%AE%80%E6%98%93%E5%AE%9E%E7%8E%B0%E8%BF%87%E7%A8%8B"><span class="nav-text">13. 内存分配的简易实现过程</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#14-%E5%8A%A0%E8%BD%BD%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F"><span class="nav-text">14. 加载用户程序</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#15-%E5%87%86%E5%A4%87%E5%AE%89%E8%A3%85%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%9A%84%E6%AE%B5%E6%8F%8F%E8%BF%B0%E7%AC%A6"><span class="nav-text">15. 准备安装用户程序的段描述符</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#16-%E7%94%A8SGDT%E5%92%8CMOVZX%E6%8C%87%E4%BB%A4%E7%A1%AE%E5%AE%9AGDT%E7%9A%84%E4%BD%8D%E7%BD%AE"><span class="nav-text">16. 用SGDT和MOVZX指令确定GDT的位置</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#17-%E5%AE%89%E8%A3%85%E6%96%B0%E6%8F%8F%E8%BF%B0%E7%AC%A6%E5%B9%B6%E7%94%9F%E6%88%90%E9%80%89%E6%8B%A9%E5%AD%90"><span class="nav-text">17. 安装新描述符并生成选择子</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#18-%E5%AE%89%E8%A3%85%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%9A%84%E6%AE%B5%E6%8F%8F%E8%BF%B0%E7%AC%A6%E5%B9%B6%E5%9B%9E%E5%A1%AB%E9%80%89%E6%8B%A9%E5%AD%90"><span class="nav-text">18. 安装用户程序的段描述符并回填选择子</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#19-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%9A%84%E6%89%A7%E8%A1%8C%E5%92%8C%E9%80%80%E5%87%BA"><span class="nav-text">19. 用户程序的执行和退出</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#20-%E5%9C%A8%E8%99%9A%E6%8B%9F%E6%9C%BA%E4%B8%8A%E8%A7%82%E5%AF%9F%E5%86%85%E6%A0%B8%E7%9A%84%E5%8A%A0%E8%BD%BD%E4%BB%A5%E5%8F%8A%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%9A%84%E6%89%A7%E8%A1%8C%E4%B8%8E%E6%8E%A8%E5%87%BA"><span class="nav-text">20. 在虚拟机上观察内核的加载以及用户程序的执行与推出</span></a></li></ol>

	</div>
</div>
	</div>
	
</div>
			</div>

			
		</div>

		<div class="main-content-footer">
			<footer class="footer mt-5 py-5 h-auto text-base text-third-text-color relative border-t-2 border-t-border-color">
    <div class="info-container py-3 text-center">
        
        <div class="text-center">
            &copy;
            
              <span>2022</span>
              -
            
            2025&nbsp;&nbsp;<i class="fa-solid fa-heart fa-beat" style="--fa-animation-duration: 0.5s; color: #f54545"></i>&nbsp;&nbsp;<a href="/">xiaoeryu</a>
            
                
                <p class="post-count space-x-0.5">
                    <span>
                        共撰写了 112 篇文章
                    </span>
                    
                </p>
            
        </div>
        
            <script data-swup-reload-script src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
            <div class="relative text-center lg:absolute lg:right-[20px] lg:top-1/2 lg:-translate-y-1/2 lg:text-right">
                
                    <span id="busuanzi_container_site_uv" class="lg:!block">
                        <span class="text-sm">访问人数</span>
                        <span id="busuanzi_value_site_uv"></span>
                    </span>
                
                
                    <span id="busuanzi_container_site_pv" class="lg:!block">
                        <span class="text-sm">总访问量</span>
                        <span id="busuanzi_value_site_pv"></span>
                    </span>
                
            </div>
        
        <div class="relative text-center lg:absolute lg:left-[20px] lg:top-1/2 lg:-translate-y-1/2 lg:text-left">
            <span class="lg:block text-sm">由 <?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="relative top-[2px] inline-block align-baseline" version="1.1" id="圖層_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1rem" height="1rem" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve"><path fill="#0E83CD" d="M256.4,25.8l-200,115.5L56,371.5l199.6,114.7l200-115.5l0.4-230.2L256.4,25.8z M349,354.6l-18.4,10.7l-18.6-11V275H200v79.6l-18.4,10.7l-18.6-11v-197l18.5-10.6l18.5,10.8V237h112v-79.6l18.5-10.6l18.5,10.8V354.6z"/></svg><a target="_blank" class="text-base" href="https://hexo.io">Hexo</a> 驱动</span>
            <span class="text-sm lg:block">主题&nbsp;<a class="text-base" target="_blank" href="https://github.com/EvanNotFound/hexo-theme-redefine">Redefine v2.8.2</a></span>
        </div>
        
        
            <div>
                博客已运行 <span class="odometer" id="runtime_days" ></span> 天 <span class="odometer" id="runtime_hours"></span> 小时 <span class="odometer" id="runtime_minutes"></span> 分钟 <span class="odometer" id="runtime_seconds"></span> 秒
            </div>
        
        
            <script data-swup-reload-script>
                try {
                    function odometer_init() {
                    const elements = document.querySelectorAll('.odometer');
                    elements.forEach(el => {
                        new Odometer({
                            el,
                            format: '( ddd).dd',
                            duration: 200
                        });
                    });
                    }
                    odometer_init();
                } catch (error) {}
            </script>
        
        
        
    </div>  
</footer>
		</div>
	</div>

	
	<div class="post-tools">
		<div class="post-tools-container">
	<ul class="article-tools-list">
		<!-- TOC aside toggle -->
		
		<li class="right-bottom-tools page-aside-toggle">
			<i class="fa-regular fa-outdent"></i>
		</li>
		

		<!-- go comment -->
		
		<li class="go-comment">
			<i class="fa-regular fa-comments"></i>
		</li>
		
	</ul>
</div>
	</div>
	

	<div class="right-side-tools-container">
		<div class="side-tools-container">
	<ul class="hidden-tools-list">
		<li class="right-bottom-tools tool-font-adjust-plus flex justify-center items-center">
			<i class="fa-regular fa-magnifying-glass-plus"></i>
		</li>

		<li class="right-bottom-tools tool-font-adjust-minus flex justify-center items-center">
			<i class="fa-regular fa-magnifying-glass-minus"></i>
		</li>

		<li class="right-bottom-tools tool-dark-light-toggle flex justify-center items-center">
			<i class="fa-regular fa-moon"></i>
		</li>

		<!-- rss -->
		

		

		<li class="right-bottom-tools tool-scroll-to-bottom flex justify-center items-center">
			<i class="fa-regular fa-arrow-down"></i>
		</li>
	</ul>

	<ul class="visible-tools-list">
		<li class="right-bottom-tools toggle-tools-list flex justify-center items-center">
			<i class="fa-regular fa-cog fa-spin"></i>
		</li>
		
		<li class="right-bottom-tools tool-scroll-to-top flex justify-center items-center">
			<i class="arrow-up fas fa-arrow-up"></i>
			<span class="percent"></span>
		</li>
		
		
	</ul>
</div>
	</div>

	<div class="image-viewer-container">
	<img src="">
</div>

	
	<div class="search-pop-overlay">
	<div class="popup search-popup">
		<div class="search-header">
			<span class="search-input-field-pre">
				<i class="fa-solid fa-keyboard"></i>
			</span>
			<div class="search-input-container">
				<input autocomplete="off" autocorrect="off" autocapitalize="off" placeholder="站内搜索您需要的内容..." spellcheck="false" type="search" class="search-input">
			</div>
			<span class="popup-btn-close">
				<i class="fa-solid fa-times"></i>
			</span>
		</div>
		<div id="search-result">
			<div id="no-result">
				<i class="fa-solid fa-spinner fa-spin-pulse fa-5x fa-fw"></i>
			</div>
		</div>
	</div>
</div>
	

</main>



<script src="/js/build/libs/Swup.min.js"></script>

<script src="/js/build/libs/SwupSlideTheme.min.js"></script>

<script src="/js/build/libs/SwupScriptsPlugin.min.js"></script>

<script src="/js/build/libs/SwupProgressPlugin.min.js"></script>

<script src="/js/build/libs/SwupScrollPlugin.min.js"></script>

<script src="/js/build/libs/SwupPreloadPlugin.min.js"></script>

<script>
    const swup = new Swup({
        plugins: [
            new SwupScriptsPlugin({
                optin: true,
            }),
            new SwupProgressPlugin(),
            new SwupScrollPlugin({
                offset: 80,
            }),
            new SwupSlideTheme({
                mainElement: ".main-content-body",
            }),
            new SwupPreloadPlugin(),
        ],
        containers: ["#swup"],
    });
</script>




	
<script src="/js/build/tools/imageViewer.js" type="module"></script>

<script src="/js/build/utils.js" type="module"></script>

<script src="/js/build/main.js" type="module"></script>

<script src="/js/build/layouts/navbarShrink.js" type="module"></script>

<script src="/js/build/tools/scrollTopBottom.js" type="module"></script>

<script src="/js/build/tools/lightDarkSwitch.js" type="module"></script>

<script src="/js/build/layouts/categoryList.js" type="module"></script>



    
<script src="/js/build/tools/localSearch.js" type="module"></script>




    
<script src="/js/build/tools/codeBlock.js" type="module"></script>




    
<script src="/js/build/layouts/lazyload.js" type="module"></script>




    
<script src="/js/build/tools/runtime.js"></script>

    
<script src="/js/build/libs/odometer.min.js"></script>

    
<link rel="stylesheet" href="/assets/odometer-theme-minimal.css">




  
<script src="/js/build/libs/Typed.min.js"></script>

  
<script src="/js/build/plugins/typed.js" type="module"></script>








    
<script src="/js/build/libs/anime.min.js"></script>





    
<script src="/js/build/tools/tocToggle.js" type="module" data-swup-reload-script=""></script>

<script src="/js/build/layouts/toc.js" type="module" data-swup-reload-script=""></script>

<script src="/js/build/plugins/tabs.js" type="module" data-swup-reload-script=""></script>




<script src="/js/build/libs/moment-with-locales.min.js" data-swup-reload-script=""></script>


<script src="/js/build/layouts/essays.js" type="module" data-swup-reload-script=""></script>





	
</body>

</html>